package com.guodu.base;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

@SuppressWarnings("rawtypes")
public class BaseDao extends HibernateDaoSupport implements IBaseDao {

	public void attachClean(Object entity) {
		if (entity == null)
			return;
		try {
			getHibernateTemplate().lock(entity, LockMode.NONE);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public Criteria createCriteria(Class entityClass, Criterion[] criterions) {
		Criteria criteria = super.getSession().createCriteria(entityClass);
		for (int i = 0; i < criterions.length; i++) {
			criteria.add(criterions[i]);
		}
		return criteria;
	}

	public void createCriteria(Criteria criteria, Map relations, Map params,
			boolean isEqual) {
		if (params != null) {
			for (Iterator it = params.entrySet().iterator(); it.hasNext();) {
				Map.Entry entry = (Map.Entry) it.next();
				if (isEqual)
					criteria.add(Restrictions.eq(entry.getKey().toString(),
							entry.getValue()));
				else {
					criteria.add(Restrictions.like(entry.getKey().toString(),
							entry.getValue()));
				}
			}
		}

		if (relations != null)
			for (Iterator it = relations.entrySet().iterator(); it.hasNext();) {
				Map.Entry entry = (Map.Entry) it.next();

				criteria.createCriteria(entry.getKey().toString()).add(
						Restrictions.eq("id", (String) entry.getValue()));
			}
	}

	public Query createQuery(Session session, String hql, Object[] values) {
		Query query = session.createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}

	public Query createQuery(String hql, Object[] values) {
		Session session = super.getSession();
		Query query =null ;
		try{
			query =createQuery(session,hql, values);
		}catch (Exception e) {
			// TODO: handle exception
		}finally{
			releaseSession(session);
		}
		return query;
	}

	public void delete(Class entityClass, Serializable id) {
		try {
			delete(findById(entityClass, id));
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void delete(Object entity) {
		if (entity == null)
			return;
		try {
			getHibernateTemplate().delete(entity);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void deleteAll(Collection entities) {
		getHibernateTemplate().deleteAll(entities);
	}

	public void deleteAllById(Class entityClass, Serializable[] ids) {
		for (int i = 0; i < ids.length; i++) {
			Object entity = findById(entityClass, ids[i]);
			getHibernateTemplate().delete(entity);
		}
	}

	public int executeUpdate(String hql) {
		return executeUpdate(hql, null);
	}

	public int executeUpdate(String hql, Object[] values) {
		Query query = createQuery(hql, values);
		return query.executeUpdate();
	}

	public void fillCriteria(Criteria cr, Object entity) {
		Field[] fs = entity.getClass().getDeclaredFields();
		try {
			for (int i = 0; i < fs.length; i++) {
				Field field = fs[i];
				field.setAccessible(true);
				String temp = field.getType().getName();
				if ((temp.indexOf("java.") == -1)
						&& (field.get(entity) != null)
						&& (!"".equals(entity))
						&& (field.get(entity).getClass().getDeclaredFields()[0]
								.get(field.get(entity)) != null)) {
					cr.add(Restrictions
							.like(field.getName(), field.get(entity)));
				}

				field.setAccessible(false);
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public List find(String hql) {
		return getHibernateTemplate().find(hql);
	}

	public List find(String hql, Object value) {
		return getHibernateTemplate().find(hql, value);
	}

	public List find(String hql, Object[] values) {
		try {
			List result = getHibernateTemplate().find(hql, values);
			return result;
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}

	}

	public List findAll(Class entityClass) {
		try {
			List list = getHibernateTemplate().find(
					"from " + entityClass.getName());
			return list;
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}

	}

	public List findByExample(Object entity) {
		try {
			List results = getHibernateTemplate().findByExample(entity);
			return results;
		} catch (RuntimeException re) {
			throw re;
		}

	}

	public Object findById(Class entityClass, Serializable id) {
		try {
			return getHibernateTemplate().get(entityClass, id);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}

	}

	@SuppressWarnings("unchecked")
	public Set findByIds(Class entityClass, Serializable[] allId) {
		Set entitySet = new HashSet();
		for (int i = 0; i < allId.length; i++) {
			entitySet.add(getHibernateTemplate().get(entityClass, allId[i]));
		}
		return entitySet;
	}

	public List findByProperty(Class entityClass, String propertyName,
			Object value) {
		try {
			String queryStr = "from " + entityClass.getName()
					+ " as model where model." + propertyName + "=?";
			return getHibernateTemplate().find(queryStr, value);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}

	}

	public Integer findCount(Class entityClass) {
		return findCount(entityClass, "", null);
	}

	public Integer findCount(Class entityClass, String where, Object[] values) {
		String hql = "select count(e) from " + entityClass.getName() + " as e "
				+ where;
		return findInt(hql, values);
	}

	public Integer findInt(String hql) {
		return Integer.valueOf( findUnique(hql, null).toString());
	}

	public Integer findInt(String hql, Object[] values) {
		return (Integer) findUnique(hql, values);
	}

	public Long findLong(String hql) {
		return (Long) findUnique(hql, null);
	}
	
	public BigDecimal findDouble(String hql) {
		Object o = findUnique(hql, null);
		if(o!=null){
		return new BigDecimal(o.toString());
		}else{
			return null;
		}
	}


	public Long findLong(String hql, Object[] values) {
		return (Long) findUnique(hql, values);
	}

	public Long findLongCount(Class entityClass) {
		return findLongCount(entityClass, "", null);
	}

	public Long findLongCount(Class entityClass, String where, Object[] values) {
		String hql = "select count(e) from " + entityClass.getName() + " as e "
				+ where;
		return findLong(hql, values);
	}

	public List findPages(Object entity, Class cls, int pageSize, int currPage,
			boolean isASC, String orderBy, String[] joins) {
		if (currPage < 1) {
			currPage = 1;
		}
		if (pageSize < 1) {
			pageSize = 1;
		}
		Session session = super.getSession();
		try {
			Criteria cr = session.createCriteria(cls);
			if (joins != null) {
				for (int i = 0; i < joins.length; i++) {
					cr.setFetchMode(joins[i], FetchMode.JOIN);
				}
			}
			if ((!"".equals(orderBy)) && (orderBy != null)) {
				if (isASC)
					cr.addOrder(Order.asc(orderBy));
				else {
					cr.addOrder(Order.desc(orderBy));
				}
			}
			if (entity != null) {
				cr.add(Example.create(entity));
				fillCriteria(cr, entity);
			}
			cr.setFirstResult((currPage - 1) * pageSize);
			cr.setMaxResults(pageSize);
			List lst = cr.list();
			return lst;
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}finally{
			releaseSession(session);
		}

	}

	public List findPages(String hql, int thisPage, int pageRecord) {
		return findPages(hql, thisPage, pageRecord, new Object[0]);
	}

	public List findPages(String hql, int thisPage, int pageRecord, List paras) {
		if (paras == null) {
			return findPages(hql, thisPage, pageRecord, new Object[0]);
		}

		return findPages(hql, thisPage, pageRecord, paras.toArray());
	}

	public List findPages(String hql, int thisPage, int pageRecord,
			Object[] paras) {
		if (thisPage < 1) {
			thisPage = 1;
		}
		if (pageRecord < 1) {
			pageRecord = 1;
		}
		Session session = super.getSession();
		try {
			Query query = session.createQuery(hql);
			if (paras != null) {
				for (int i = 0; i < paras.length; i++) {
					query.setParameter(i, paras[i]);
				}
			}

			query.setFirstResult((thisPage - 1) * pageRecord);
			query.setMaxResults(pageRecord);
			List lst = query.list();
			return lst;
		} catch (RuntimeException e) {
			e.printStackTrace();
			e.printStackTrace();
			throw e;
		}finally{
			releaseSession(session);
		}

	}

	public Object findUnique(String hql) {
		return findUnique(hql, new Object[0]);
	}

	public Object findUnique(final String hql, final Object[] values) {
		try {
			Object result = getHibernateTemplate().execute(
					new HibernateCallback() {
						public Object doInHibernate(Session s)
								throws HibernateException, SQLException {
							Query query = BaseDao.this.createQuery(s, hql,
									values);
							return query.uniqueResult();
						}
					});
			return result;
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}

	}

	public Object findUniqueByProperty(Class entityClass, String propertyName,
			Object value) {
		try {
			createCriteria(entityClass,
					new Criterion[] { Restrictions.eq(propertyName, value) })
					.setMaxResults(1);
			Object result = createCriteria(entityClass,
					new Criterion[] { Restrictions.eq(propertyName, value) })
					.uniqueResult();
			return result;
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}

	}

	public boolean isPropertyUnique(Class entityClass, String propertyName,
			Object newValue, Object orgValue) {
		if ((newValue == null) || (newValue.equals(orgValue))) {
			return true;
		}

		Object object = findUniqueByProperty(entityClass, propertyName,
				newValue);
		return object == null;
	}

	public Object load(Class entityClass, Serializable id) {
		return getHibernateTemplate().load(entityClass, id);
	}

	public List loadAll(Class entityClass) {
		return getHibernateTemplate().loadAll(entityClass);
	}

	public Object merge(Object entity) {
		try {
			Object result = getHibernateTemplate().merge(entity);
			return result;
		} catch (RuntimeException re) {
			throw re;
		}

	}

	public void save(Object entity) {
		try {
			getHibernateTemplate().save(entity);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void saveAll(Collection entities) {
		if ((entities == null) || (entities.size() < 1)) {
			return;
		}

		for (Iterator localIterator = entities.iterator(); localIterator
				.hasNext();) {
			Object entity = localIterator.next();
			save(entity);
		}
	}

	public void saveOrUpdate(Object entity) {
		try {
			getHibernateTemplate().saveOrUpdate(entity);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void saveOrUpdateAll(Collection entities) {
		try {
			getHibernateTemplate().saveOrUpdateAll(entities);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void update(Object entity) {
		try {
			super.getHibernateTemplate().update(entity);
		} catch (RuntimeException e) {
			e.printStackTrace();
			throw e;
		}
	}
}
